package com.ericsson.enap.modules.kpi.thread;

import com.ericsson.common.util.AviatorUtil;
import com.ericsson.common.util.FileUtil;
import com.ericsson.common.util.FormulaConvert;
import com.ericsson.common.util.SpringUtils;
import com.ericsson.enap.modules.kpi.entity.EnipFormula;
import com.ericsson.enap.modules.kpi.entity.EnipKpiDataResult;
import com.ericsson.enap.modules.kpi.entity.EnipMeasInfo;
import com.ericsson.enap.modules.kpi.entity.VgcFifKpi;
import com.ericsson.enap.modules.kpi.service.EnipKpiFileProcess;
import com.googlecode.aviator.Expression;
import org.slf4j.Logger;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * VGC十五分钟KPI数据处理线程
 */
public class VgcFifKpiDataProcessThread implements Runnable {

    private EnipKpiFileProcess kpiFileProcess;
    private Logger log;
    private MongoTemplate mongoTemplate;
    private List<EnipFormula> formulas;
    private String typeStr;
    private Date date;
    private VgcFifKpi vgcFifKpi;
    private String vgckpiDownloadDir;

    public VgcFifKpiDataProcessThread(VgcFifKpi vgcFifKpi, String typeStr, List<EnipFormula> formulas, Date date, Logger log, String vgckpiDownloadDir) {
        this.kpiFileProcess = SpringUtils.getBean("kpiFileProcess" + typeStr + "Impl");
        this.mongoTemplate = (MongoTemplate) SpringUtils.getBean("mongoTemplate");
        this.vgcFifKpi = vgcFifKpi;
        this.typeStr = typeStr;
        this.formulas = formulas;
        this.date = date;
        this.log = log;
        this.vgckpiDownloadDir = vgckpiDownloadDir;
    }

    @Override
    public void run() {
        List<EnipMeasInfo> curDataObj = getData(0, this.vgcFifKpi);
        countAndInsertToDB(curDataObj);
    }

    private List<EnipMeasInfo> getData(int delay, VgcFifKpi vgcFifKpi) {
        try {
            String filePathString = this.vgckpiDownloadDir + File.separator + this.typeStr + File.separator + vgcFifKpi.getId() + File.separator;
            File file = downloadFilesByFTP(vgcFifKpi, delay, filePathString);
            if (file != null) {
                return filterAndGetData(file);
            } else {
                log.info(" null");
            }
        } catch (Exception e) {
            log.error("KpiDataProcessTask getData method:" + e.getMessage() + "netType is :" + this.typeStr, e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从ftp服务器下载文件
     *
     * @param vgcFifKpi
     * @param delay
     * @return
     * @throws Exception
     */
    private File downloadFilesByFTP(VgcFifKpi vgcFifKpi, int delay, String filePathString) throws Exception {
        File filePath = new File(filePathString);
        FileUtil.newDirs(filePath);
        // 删除上一批次下载的文件
        if (filePath.exists()) {
            File[] oldxmlTargetFiles = filePath.listFiles();
            for (File file : oldxmlTargetFiles) {
                if (file.exists() && file.isFile()) {
                    log.info("|||||||||||||||||||||||||||||||||||||||||||||||" + file.getName());
                    file.delete();
                }
            }
        }
        return kpiFileProcess.download(vgcFifKpi, filePathString, log);
    }

    /**
     * 通过各个kpiFileProcess的实现类的analysis方法解析文件
     *
     * @param file
     * @return
     */
    private List<EnipMeasInfo> filterAndGetData(File file) {
        log.info(vgcFifKpi.getName() + "analysis start");
        List<EnipMeasInfo> enipMeasInfoList = kpiFileProcess.analysis(file, log);
        log.info(vgcFifKpi.getName() + "analysis end" + enipMeasInfoList.size());
        return enipMeasInfoList;
    }

    private void countAndInsertToDB(Object curDataObj) {
        if (curDataObj == null) {
            log.error(typeStr + ":" + vgcFifKpi.getName() + "curDataObj null");
            return;
        }
        List<EnipMeasInfo> measInfos = (List<EnipMeasInfo>) curDataObj;
        String beginTime = measInfos.get(0).getBeginTime();
        Query query = Query.query(Criteria.where("dateTime").is(beginTime));
        query.addCriteria(Criteria.where("netid").is(vgcFifKpi.getId().toString()));
        long count = this.mongoTemplate.count(query, "vgckpi_16_" + typeStr.toLowerCase());//统计查询count查询
        log.info("count:" + count + "beginTime:" + beginTime + "netid:" + vgcFifKpi.getId().toString());
        if (count == 0) {
            //循环每一个公式
            Map<String, String> resultMap = new HashMap<>();
            EnipKpiDataResult kpiDataResult = new EnipKpiDataResult();
            try {
                for (EnipFormula formula : formulas) {
                    try {
                        //1 获取编译后的表达式对象
                        Expression compiledExp = formula.getExpression();
                        //2 取出计算因子
                        List<String> vars = compiledExp.getVariableFullNames();
                        //计算公式用的map,key 为计算因子，value 为 对应的值
                        Map<String, Object> dataMap = new HashMap<>();
                        for (String var : vars) {
                            String perVar = FormulaConvert.restoreFormula(var);
                            for (EnipMeasInfo m : measInfos) {
                                String result = parseData(m, perVar);
                                if (null != result && !result.equals("0.0")) {
                                    dataMap.put(var, Double.valueOf(result));
                                }
                            }
                            if (!dataMap.containsKey(var)) {
                                dataMap.put(var, Double.valueOf("0.0"));
                            }
                        }
                        if (dataMap.size() > 0) {
                            Object result = AviatorUtil.execute(compiledExp, dataMap, formula);
                            resultMap.put(String.valueOf(formula.getId()), String.valueOf(result));
                        }
                    } catch (Exception ex) {
                        log.error(typeStr + ":" + vgcFifKpi.getName() + ex.getCause());
                    }
                }
            } catch (Exception e) {
                log.error(typeStr + ":" + vgcFifKpi.getName() + e.getCause());
            }
            if (resultMap.size() > 0) {
                kpiDataResult.setDateTime(beginTime);
                kpiDataResult.setNetid(String.valueOf(vgcFifKpi.getId()));
                kpiDataResult.setPoolid(String.valueOf(vgcFifKpi.getPool_id()));
                kpiDataResult.setNetName(vgcFifKpi.getName());
                kpiDataResult.setKpiMap(resultMap);
                log.info("insert data to MongoDB " + typeStr + ":" + vgcFifKpi.getName() + " start ...");
                mongoTemplate.insert(kpiDataResult, "vgckpi_16_" + typeStr.toLowerCase());
                log.info("insert data to MongoDB " + typeStr + ":" + vgcFifKpi.getName() + " end ...");
            } else {
                log.info("nodata：" + vgcFifKpi.getName());
            }
        }
    }

    /**
     * 根据公式中的规则 解析数据
     *
     * @param m
     * @param perVar
     * @return
     */
    private String parseData(EnipMeasInfo m, String perVar) {
        Map<String, String> mvMap = m.getMeasTypeMap();
        String tempVar = perVar;
        int count = 0;
        double calResult = 0;
        if (perVar.contains("avg_")) {//判断公式是否需要计算平均值
            perVar = perVar.replace("avg_", "");
        }//不包含条件
        if (mvMap.containsKey(perVar)) {
            calResult = calResult + Double.parseDouble(mvMap.get(perVar));
            if (tempVar.contains("avg_")) {//包含计算平均值的  计数器
                count = count + 1;
            }
        }
        if (count > 0) {
            return calResult / count + "";
        } else {
            return calResult + "";
        }
    }
}
